
#include <cstdlib>
#include <iostream>

#include <boost/thread.hpp>
#include <boost/asio.hpp>
#include <wrapper.hpp>
#include <xbase_utility.hpp>
#include <protocol.hpp>

using namespace std;
using namespace xbase;
using namespace boost::asio;

// 一直发送关闭扫描器请求
char req_buf[256];
int req_size;

int n = 0;

char * ip_str=0;
char * port_str=0;

void send_request()
{
	const int resp_size = 1024;
	char resp_buf[resp_size];

	boost::asio::io_service io_service;
	boost::asio::ip::tcp::resolver resolver(io_service);
	boost::asio::ip::tcp::resolver::query query(ip_str, port_str);
	boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);

	boost::asio::ip::tcp::socket s(io_service);
	s.connect(*iter);

	// send
	const time_t start_time = cur_micro_seconds();
	for(int i=0; i<n; ++i)
	{
		boost::asio::write(s, boost::asio::buffer(req_buf, req_size));
		s.read_some(boost::asio::buffer(resp_buf, resp_size));
	}
	const time_t end_time = cur_micro_seconds();

	// close socket
	s.close();

	const time_t used_time = end_time - start_time;
	const int used_seconds = used_time / (1000 * 1000);
	const int used_us = used_time % (1000 * 1000);
	char buf[256];
	snprintf(buf, 256, "%d.%06d", used_seconds, used_us);

	std::cout << n << " requests sent, used " << buf << " seconds" << std::endl;
	double n_per_second = ((double)n) * 1000.0 * 1000.0 / (double)used_time;
	std::cout << "average " << n_per_second << " requests per second" << std::endl;
}

// void async_send_request()
// {
// 	const int resp_size = 1024;
// 	char resp_buf[resp_size];

// 	boost::asio::io_service io_service;
// 	boost::asio::ip::tcp::resolver resolver(io_service);
// 	boost::asio::ip::tcp::resolver::query query(ip_str, port_str);
// 	boost::asio::ip::tcp::resolver::iterator iter = resolver.resolve(query);

// 	boost::asio::ip::tcp::socket s(io_service);
// 	s.connect(*iter);

// 	// send
// 	const time_t start_time = cur_micro_seconds();
// 	for(int i=0; i<n; ++i)
// 	{
// 		boost::asio::async_write(s,
// 					 boost::asio::buffer(req_buf, req_size),
// 					 boost::bind(&boost::asio::ip::tcp::socket::read_some,
// 						     this,
// 						     boost::asio::buffer(resp_buf, resp_size),
// 						     boost::asio::placeholders::error));
// 	}
// 	const time_t end_time = cur_micro_seconds();

// 	// close socket
// 	s.close();

// 	const time_t used_time = end_time - start_time;
// 	const int used_seconds = used_time / (1000 * 1000);
// 	const int used_us = used_time % (1000 * 1000);
// 	char buf[256];
// 	snprintf(buf, 256, "%d.%06d", used_seconds, used_us);

// 	std::cout << n << " requests sent, used " << buf << " seconds" << std::endl;
// 	double n_per_second = ((double)n) * 1000.0 * 1000.0 / (double)used_time;
// 	std::cout << "average " << n_per_second << " requests per second" << std::endl;
// }

int main(int argc, char**argv)
{
	if(argc != 5)
	{
		std::cout << argv[0] << " <requests_number> <threads_number> <server_ip> <port>" << std::endl;
		return -1;
	}

	// init request
	req_size = 0;
	
	header_wrapper *header = reinterpret_cast<header_wrapper*>(req_buf);
	header->m_magic = XBASE_PROTOCOL_MAGIC;
	header->m_version = 1;
	header->m_type = SCAN_CLOSE_REQ;
	header->m_sequence_number.set(0);
	header->m_data_length.set(0);
	req_size = header->bytes();

	integer_wrapper<uint32_t, kb::network_byteorder> *version = reinterpret_cast<integer_wrapper<uint32_t, kb::network_byteorder> *>(req_buf + req_size);
	version->set(0);
	req_size += version->bytes();
	
	string_wrapper<uint32_t, char, kb::network_byteorder> *tablet_name = reinterpret_cast<string_wrapper<uint32_t, char, kb::network_byteorder> *>(req_buf + req_size);
	tablet_name->fill(std::string("no_this_tablet"));
	req_size += tablet_name->bytes();

	integer_wrapper<uint64_t, kb::network_byteorder> *scanner_id = reinterpret_cast<integer_wrapper<uint64_t, kb::network_byteorder> *>(req_buf + req_size);
	scanner_id->set(920);
	req_size += scanner_id->bytes();

	header->m_data_length.set(req_size - header->bytes());

	n = atoi(argv[1]);
	const int threads = atoi(argv[2]);
	ip_str = argv[3];
	port_str = argv[4];
	
	if(n <= 0 || threads <= 0)
	{
		return -1;
	}
	
	boost::thread_group group;
	for(int i=0; i<threads; ++i)
	{
		group.create_thread(&send_request);
	}
	
	group.join_all();
	
	return 0;
}
